import random
import math
import numpy as NP

def normaN(nDim,x1,x2):
	'''
	Calcola la metrica euclidea 
	N dimensionale tra due vettori x1 e x2
	__DEPRECATED__
	'''
	summ =0
	
	for i in range(nDim):
		summ += math.pow((x1[i] - x2[i]),2)	
	return math.sqrt(summ)
	
def K_Means(patterns,centr,nCentr,nDim):
	'''
	Calcolo dell'aggiornamento della coordinata metodo k means
	ricordando che centr contiene le linste dei pattern che appartengono
	a ciascun centroide
	'''
	cNew = NP.zeros(nDim)
	
	### condizione sulla mancata appartenenza
	
	for j in range(nDim):  
		for i in range(int(nCentr)):
			cNew[j] += patterns[centr[0][i]][j]
		if(nCentr != 0):
			cNew[j] = cNew[j]/nCentr  
		else:	
			if(random.random() < 0.5):
				cNew[j] += 0.01 *random.random()  
			 
			else:
				cNew[j] -= 0.01 *random.random()
				
	return cNew

def getBestAssociation(Patterns, Pattern2Cluster):
	'''
	Restituisce una tupla formata da:
	 - una lista di 2 elementi, associando l'i-esimo cluster all'etichetta +1 o -1
	   in base a quale delle due associazioni fornisce il minor numero di errori
	 - il numero di errori con l'associazione scelta
	 - il numero di errori con l'altra associazione
	'''
	### il numero di errori assegnando il centroide 0 all'etichetta -1 e il centroide 1 all'etichetta +1
	errors_0_minus_1_plus = 0
	### il numero di errori assegnando il centroide 0 all'etichetta +1 e il centroide 1 all'etichetta -1
	errors_0_plus_1_minus = 0
	
	for i in range(len(Patterns)):
		if ((Patterns[i]._real_label == -1 and Pattern2Cluster[i] == 0) or (Patterns[i]._real_label == +1 and Pattern2Cluster[i] == 1)):
			errors_0_plus_1_minus += 1
		else:
			errors_0_minus_1_plus += 1
	
	if (errors_0_minus_1_plus < errors_0_plus_1_minus):
		return [-1, 1], errors_0_minus_1_plus, errors_0_plus_1_minus
	else:
		return [1, -1], errors_0_plus_1_minus, errors_0_minus_1_plus

def getConfusionMatrix(Patterns, Pattern2Cluster, Association):
	'''
	Restituisce la matrice di confusione. Il primo indice indica il numero di riga, il secondo quello di colonna
	A/P = Actual/Predicted
	---------------
	|A/P| -1 | +1 |
	|---|----|----|
	|-1 | 21 | 11 |
	|---|----|----|
	|+1 | 13 | 28 |
	|---|----|----|
	'''
	M = NP.zeros((2,2))
	
	for i in range(len(Patterns)):
		r = (Patterns[i]._real_label + 1)/2
		c = (Association[Pattern2Cluster[i]] + 1) / 2
		M[r][c] += 1
		
	return M

def calculateRandIndex(Patterns, Pattern2Cluster):
	'''
	Calcola e restituisce il rand index
	'''
	a = b = c = d = 0
	
	for i in range(len(Patterns)):
		for j in range(len(Patterns)):
			if (i != j):
				if (Patterns[i]._real_label == Patterns[j]._real_label):
					if (Pattern2Cluster[i] == Pattern2Cluster[j]):
						a += 1
					else:
						c += 1
				else:
					if (Pattern2Cluster[i] == Pattern2Cluster[j]):
						d += 1
					else:
						b += 1
						
	print "a = ", a, " b = ", b, " c = ", c, " d = ", d
	
	return (float)(a + b)/(a + b + c + d)

def norma(x1, x2):
	return math.sqrt(sum(pow(x1-x2,2)))
	
def flip(p):
	'''
	Metodo che restituisce true con probabilita' p
	'''
	return random.random() < p
